#include "udp_io.h"
#ifdef WIN32
#define usleep(x) Sleep(x)
#endif
#ifdef __linux__
#include <stdexcept>
#endif
#include "Log.h"
#include "msg_to_aliyun_by_acl.h"
#include "email.h"

#include "acl_cpp/stdlib/string.hpp"

//c++ version
#include "HMAC_SHA1.h"
#include "Base64.h"
//c version
#include "HMACSHA1.h"
//
#include "strchange.h"

class PushThread : public acl::thread
{
public:
    PushThread(UdpIO *ptr_STC_);
    ~PushThread();
    void* run();
private:
    bool running;
    UdpIO *ptr_STC;
};

PushThread::PushThread(UdpIO *ptr_STC_)
    : running(true)
    , ptr_STC(ptr_STC_)
{

}

PushThread::~PushThread()
{
    running = false;
    ptr_STC = NULL;
}

void* PushThread::run()
{
    while (running)
    {
        if(NULL!=ptr_STC){
            ptr_STC->push();
        }
        usleep(10);
    }
    return NULL;
}

UdpIO::UdpIO(bool msg_,bool mail_,std::string addr/*="127.0.0.1"*/,int port/*=60005*/)
    : running(true)
	, queueforwar(QueueDataSingle<EventForWaring>::getInstance())
	, msg_to_ali_ptr(new MsgToAliyun())
	, email_ptr(new Email())
	, msgFlag(msg_)
	, mailFlag(mail_)
	, ControlCheckKey("pyfree")
{
    acl_lib_init();
    char  local[64]={0};
	snprintf(local, sizeof(local), "%s:%d",addr.c_str(),port);
    local_addr = std::string(local);
	ptr_push = new PushThread(this);
	ptr_push->start();
}

UdpIO::~UdpIO()
{
    running = false;
}

void* UdpIO::run()
{
    ACL_VSTREAM *stream = acl_vstream_bind(local_addr.c_str(), 2, 0);  /* 绑定 UDP 套接口 */
    if (stream == NULL) {
		CLogger::createInstance()->Log(MsgError,"acl_vstream_bind %s error %s int UdpIO::run()",
			local_addr.c_str(), acl_last_serror());
		return NULL;
	}
    printf("bind udp addr %s ok\r\n", local_addr.c_str());
    unsigned char buf[256] = {0};
    int ret = 0;
	while (running)
    {
        ret = acl_vstream_read(stream, buf, 256);
		if (ret == ACL_VSTREAM_EOF) {
			printf("acl_vstream_read error %s\r\n",
				acl_last_serror());
			//重置udp
			acl_vstream_close(stream);
			stream = acl_vstream_bind(local_addr.c_str(), 2, 0);  /* 绑定 UDP 套接口 */
			if (stream == NULL) {
				CLogger::createInstance()->Log(MsgError,"acl_vstream_bind %s error %s int UdpIO::run()",
					local_addr.c_str(), acl_last_serror());
				break;
			}
		} else{
			buf[ret] = 0;
            AddFrameDef((const unsigned char *)buf,ret);
        }
        usleep(10);
    }
    
    acl_vstream_close(stream);
    return NULL;
}

int UdpIO::AddFrameDef(const unsigned char *pBuf, int len)
{
	//json转换
	acl::json json;
	if(!toJSon(json,pBuf,len))
	{
		return -1;
	}
	EventForWaring efw;
	int ret = 0;
	acl::json_node* iter = json.first_node();
	while (iter)
	{
		if (iter->tag_name())
		{
			if (0 == strcmp("send", iter->tag_name())) 
			{
				efw.send_ = static_cast<pyfree::EventWay>(atoi(iter->get_text()));
				ret++;
			}
			else if (0 == strcmp("ETime", iter->tag_name())) 
			{
				efw.execTime = iter->get_text();
				ret++;
			}
			else if (0 == strcmp("ADesc", iter->tag_name())) 
			{
				efw.area_desc = iter->get_text();
				ret++;
			}
			else if (0 == strcmp("EType", iter->tag_name())) 
			{
				efw.desc = iter->get_text();
				ret++;
			}
			else if (0 == strcmp("ELevel", iter->tag_name())) 
			{
				efw.levelDesc = iter->get_text();
				ret++;
			}
			else if (0 == strcmp("TaskID", iter->tag_name())) 
			{
				efw.taskDesc = iter->get_text();
				ret++;
			}
			else if (0 == strcmp("dev_desc", iter->tag_name())) 
			{
				efw.devDesc = iter->get_text();
				ret++;
			}
			else if (0 == strcmp("ponit_desc", iter->tag_name())) 
			{
				efw.pDesc = iter->get_text();
				ret++;
			}
			else if (0 == strcmp("ValDesc", iter->tag_name())) 
			{
				efw.valDesc = iter->get_text();
				ret++;
			}
			else 
			{
				printf("tag: %s, value: %s\r\n", iter->tag_name(), iter->get_text());
			}
		}
		iter = json.next_node();
	}
	if(ret>=9){
		queueforwar->add(efw);
	}
	return 1;
};

bool UdpIO::toJSon(acl::json &json,const unsigned char *pBuf, int len)
{
	try {
		json.update((const char *)pBuf);
	}
	catch (...) 
	{
		CLogger::createInstance()->Log(MsgError,
			"UdpIO::toJSon for json.update error"
			",please make sure the[%s,%d] is right,[%s %s %d]!"
			, (char*)pBuf, len
			, __FILE__, __FUNCTION__, __LINE__);
		return false;
	}
	//输出查看
	acl::string aclbuf;
	try {
		json.build_json(aclbuf);
		#ifdef WIN32
		std::string acl_buf = std::string(aclbuf.c_str(),aclbuf.length());
		acl_buf = UTF_82ASCII(acl_buf);
		CLogger::createInstance()->Log(MsgInfo
			, "UdpIO::toJSon Received:%s", acl_buf.c_str());
		#else
		CLogger::createInstance()->Log(MsgInfo
			, "UdpIO::toJSon Received:%s", aclbuf.c_str());
		#endif 
	}
	catch (...) 
	{
		CLogger::createInstance()->Log(MsgError,
			"UdpIO::AddFrameDef for init data writing and json.build_json Exception"
			",[%s %s %d]!"
			, __FILE__, __FUNCTION__, __LINE__);
		return false;
	}
	return true;
}

bool UdpIO::checkCode(EventForWaring efw)
{
	char bufComment[256] = { 0 };
	sprintf(bufComment, "%s;%s;%s;%s"
		, efw.taskDesc.c_str()
		, efw.devDesc.c_str()
		, efw.pDesc.c_str()
		, efw.valDesc.c_str());
	std::string sortQueryStringTmp = std::string(bufComment);
	//生成签名
	char hmac_buf[256] = { 0 };
	hmac_sha((char*)(ASCII2UTF_8(ControlCheckKey)).c_str(), static_cast<int>(ControlCheckKey.length()) + 1
		, (char*)ASCII2UTF_8(sortQueryStringTmp).c_str(), static_cast<int>(sortQueryStringTmp.length()), hmac_buf, 20);
	std::string hmac = std::string(hmac_buf, strlen(hmac_buf));
	hmac = pyfree::Encode((const unsigned char*)hmac.c_str(), static_cast<int>(hmac.length()));
	if (0 != strcmp(efw.code_xf.c_str(), hmac.c_str())) 
	{
		CLogger::createInstance()->Log(MsgInfo, "rec hmac:%s is not map create hmac:%s"
			, efw.code_xf.c_str(), hmac.c_str());
		return false;
	}
	return true;
}

void UdpIO::push()
{
	EventForWaring efw;
	if (queueforwar->pop(efw)) 
	{
		/*
		*3==efw.send,do email msg log
		*2==efw.send,do msg log
		*1==efw.send,do log
		*/	
		if (efw.send_>= AlarmForEMail&&mailFlag&&email_ptr->isMapMailTime())
		{
			//you code
			email_ptr->send_email(efw);
		}
		if(efw.send_ >= AlarmForSMS&&msgFlag&&msg_to_ali_ptr->isMapMsgTime())
		{
			msg_to_ali_ptr->sendMsg(efw);
			usleep(100);//
		}
		if (efw.send_ >= AlarmForLog)
		{
			//
			char buf[512] = { 0 };
			sprintf(buf, "Time(%s),ADesc(%s),EType(%s),ELevel(%s),TaskID(%s)"
				",DevID(%s),PID(%s),ValDesc(%s)"
				, efw.execTime.c_str()
				, efw.area_desc.c_str()
				, efw.desc.c_str()
				, efw.levelDesc.c_str()
				, efw.taskDesc.c_str()
				, efw.devDesc.c_str()
				, efw.pDesc.c_str()
				, efw.valDesc.c_str());
			#ifdef WIN32
			std::string buf_str = std::string(buf);
			buf_str = UTF_82ASCII(buf_str);
			CLogger::createInstance()->Log(MsgInfo, "%s", buf_str.c_str());
			#else
			CLogger::createInstance()->Log(MsgInfo, "%s", buf);
			#endif
		}
	}
}